package com.bestcem.xm.txtanls.util;

import com.bestcem.xm.bi.grpc.v1.enums.DataTypeEnum;
import com.bestcem.xm.bi.grpc.v1.enums.DateTypeEnum;
import com.bestcem.xm.bi.grpc.v1.enums.OptionEnum;
import com.bestcem.xm.bi.grpc.v1.services.Filter;
import com.bestcem.xm.txtanls.entity.pojo.ProjectDO;
import com.bestcem.xm.txtanls.entity.pojo.ProjectFieldDO;
import com.bestcem.xm.txtanls.enums.ColumnDataTypeEnum;
import com.bestcem.xm.txtanls.enums.DatasourceEnum;
import com.bestcem.xm.txtanls.grpc.client.ClickhouseGrpcService;
import com.bestcem.xm.txtanls.service.dto.train.ClickHouseDTO;
import com.bestcem.xm.txtanls.service.dto.train.ClickhouseColumnDTO;
import com.bestcem.xm.txtanls.service.dto.worktable.ColumnDTO;
import com.bestcem.xm.txtanls.service.impl.AsyncTaskServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author XiaoYunSong <ys.xiao@idiaoyan.com>
 * @version v1.0
 * @date 2021/6/23 13:22
 */
@Slf4j
@Component
public class ClickhouseUtil {
    @Resource
    private ClickhouseGrpcService clickhouseGrpcService;

    /**
     * 获取表数据长度时查询clickhouse需要的列信息
     *
     * @param project      项目信息
     * @param columnDTOMap 项目对应worktable全部column
     * @return 查询clickhouse需要的列信息
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/7/28 17:29
     */
    public List<ClickhouseColumnDTO> getWorktableDataTotalColumns(ProjectDO project,
                                                                  Map<String, ColumnDTO> columnDTOMap, int datasourceType) {
        List<ClickhouseColumnDTO> clickhouseColumnDTOList = new ArrayList<>();
        boolean isSurvey = datasourceType == DatasourceEnum.SURVEY.getIndex()
                || !ObjectUtils.isEmpty(project.getSurveyId());

        List<ProjectFieldDO> textFieldList = project.getTextFieldList();
        if (!CollectionUtils.isEmpty(textFieldList)) {
            for (ProjectFieldDO textField : textFieldList) {
                // 填充待分析的文本字段
                ColumnDTO columnDTO;
                if (isSurvey) {
                    columnDTO = columnDTOMap.get(textField.getValue());
                } else {
                    columnDTO = columnDTOMap.get(textField.getId());
                }
                if (Objects.nonNull(columnDTO)) {
                    ClickhouseColumnDTO clickhouseColumnDTO = new ClickhouseColumnDTO();
                    clickhouseColumnDTO.setColumnId(columnDTO.getId());
                    clickhouseColumnDTO.setCol(columnDTO.getCol());
                    clickhouseColumnDTO.setName(textField.getValue());
                    clickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(columnDTO.getDType()));
                    clickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
                    clickhouseColumnDTOList.add(clickhouseColumnDTO);
                }
            }
        }

        // 填充分析的时间字段
        ColumnDTO timeColumnDTO;
        if (isSurvey) {
            timeColumnDTO = columnDTOMap.get(project.getTimeFieldName());
        } else {
            timeColumnDTO = columnDTOMap.get(project.getId());
        }
        if (Objects.nonNull(timeColumnDTO)) {
            ClickhouseColumnDTO timeClickhouseColumnDTO = new ClickhouseColumnDTO();
            timeClickhouseColumnDTO.setColumnId(timeColumnDTO.getId());
            timeClickhouseColumnDTO.setCol(timeColumnDTO.getCol());
            timeClickhouseColumnDTO.setName(project.getTimeFieldName());
            timeClickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(timeColumnDTO.getDType()));
            timeClickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(timeClickhouseColumnDTO);
        }

        return clickhouseColumnDTOList;
    }

    /**
     * 定量数据项目待训练的字段转换为查询clickhouse需要的列信息
     *
     * @param project      项目信息
     * @param textField    待训练的字段
     * @param columnDTOMap 项目对应worktable全部column
     * @return 查询clickhouse需要的列信息
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/7/21 15:17
     */
    public List<ClickhouseColumnDTO> getStaticClickhouseColumns(ProjectDO project, ProjectFieldDO textField,
                                                                Map<String, ColumnDTO> columnDTOMap) {
        List<ClickhouseColumnDTO> clickhouseColumnDTOList = new ArrayList<>();

        // 填充待分析的文本字段
        ColumnDTO columnDTO = columnDTOMap.get(textField.getId());
        if (Objects.nonNull(columnDTO)) {
            ClickhouseColumnDTO clickhouseColumnDTO = new ClickhouseColumnDTO();
            clickhouseColumnDTO.setColumnId(columnDTO.getId());
            clickhouseColumnDTO.setCol(columnDTO.getCol());
            clickhouseColumnDTO.setName(textField.getValue());
            clickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(columnDTO.getDType()));
            clickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(clickhouseColumnDTO);
        }
        // 填充分析的时间字段
        ColumnDTO timeColumnDTO = columnDTOMap.get(project.getTimeFieldId());
        if (Objects.nonNull(timeColumnDTO)) {
            ClickhouseColumnDTO timeClickhouseColumnDTO = new ClickhouseColumnDTO();
            timeClickhouseColumnDTO.setColumnId(timeColumnDTO.getId());
            timeClickhouseColumnDTO.setCol(timeColumnDTO.getCol());
            timeClickhouseColumnDTO.setName(project.getTimeFieldName());
            timeClickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(timeColumnDTO.getDType()));
            timeClickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(timeClickhouseColumnDTO);
        }

        return clickhouseColumnDTOList;
    }

    /**
     * 非定量数据项目待训练的字段转换为查询clickhouse需要的列信息
     *
     * @param project      项目信息
     * @param textField    待训练的字段
     * @param columnDTOMap 项目对应worktable全部column
     * @return 查询clickhouse需要的列信息
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/7/21 15:17
     */
    public List<ClickhouseColumnDTO> getIncrementClickhouseColumns(ProjectDO project,
                                                                   ProjectFieldDO textField,
                                                                   Map<String, ColumnDTO> columnDTOMap) {
        List<ClickhouseColumnDTO> clickhouseColumnDTOList = new ArrayList<>();

        // 填充待分析的文本字段
        ColumnDTO columnDTO = columnDTOMap.get(textField.getId());
        if (Objects.nonNull(columnDTO)) {
            ClickhouseColumnDTO clickhouseColumnDTO = new ClickhouseColumnDTO();
            clickhouseColumnDTO.setColumnId(columnDTO.getId());
            clickhouseColumnDTO.setCol(columnDTO.getCol());
            clickhouseColumnDTO.setName(textField.getValue());
            clickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(columnDTO.getDType()));
            clickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(clickhouseColumnDTO);
        }
        // 填充分析的时间字段
        ColumnDTO timeColumnDTO = columnDTOMap.get(project.getTimeFieldId());
        if (Objects.nonNull(timeColumnDTO)) {
            ClickhouseColumnDTO timeClickhouseColumnDTO = new ClickhouseColumnDTO();
            timeClickhouseColumnDTO.setColumnId(timeColumnDTO.getId());
            timeClickhouseColumnDTO.setCol(timeColumnDTO.getCol());
            timeClickhouseColumnDTO.setName(project.getTimeFieldName());
            timeClickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(timeColumnDTO.getDType()));
            timeClickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(timeClickhouseColumnDTO);
        }

        return clickhouseColumnDTOList;
    }

    /**
     * 问卷项目待训练的字段转换为查询clickhouse需要的列信息
     *
     * @param project      项目信息
     * @param textField    待训练的字段
     * @param columnDTOMap 项目对应worktable全部column
     * @return 查询clickhouse需要的列信息
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/7/21 15:17
     */
    public List<ClickhouseColumnDTO> getSurveyClickhouseColumns(ProjectDO project, ProjectFieldDO textField,
                                                                Map<String, ColumnDTO> columnDTOMap) {
        List<ClickhouseColumnDTO> clickhouseColumnDTOList = new ArrayList<>();

        // 填充待分析的文本字段
        ColumnDTO columnDTO = columnDTOMap.get(textField.getValue());
        if (Objects.nonNull(columnDTO)) {
            ClickhouseColumnDTO clickhouseColumnDTO = new ClickhouseColumnDTO();
            clickhouseColumnDTO.setColumnId(columnDTO.getId());
            clickhouseColumnDTO.setCol(columnDTO.getCol());
            clickhouseColumnDTO.setName(textField.getValue());
            clickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(columnDTO.getDType()));
            clickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(clickhouseColumnDTO);
        }
        // 填充分析的时间字段
        ColumnDTO timeColumnDTO = columnDTOMap.get(project.getTimeFieldName());
        if (Objects.nonNull(timeColumnDTO)) {
            ClickhouseColumnDTO timeClickhouseColumnDTO = new ClickhouseColumnDTO();
            timeClickhouseColumnDTO.setColumnId(timeColumnDTO.getId());
            timeClickhouseColumnDTO.setCol(timeColumnDTO.getCol());
            timeClickhouseColumnDTO.setName(project.getTimeFieldName());
            timeClickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(timeColumnDTO.getDType()));
            timeClickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(timeClickhouseColumnDTO);
        }
        // 问卷类型填充问卷特有时间标识字段 "time" 和 特有唯一标识字段 "seq"
        ColumnDTO collectionTimeColumnDTO = columnDTOMap.get(AsyncTaskServiceImpl.TIME);
        if (Objects.nonNull(collectionTimeColumnDTO)) {
            ClickhouseColumnDTO collectionTimeClickhouseColumnDTO = new ClickhouseColumnDTO();
            collectionTimeClickhouseColumnDTO.setColumnId(collectionTimeColumnDTO.getId());
            collectionTimeClickhouseColumnDTO.setCol(collectionTimeColumnDTO.getCol());
            collectionTimeClickhouseColumnDTO.setName(AsyncTaskServiceImpl.COLLECTION_TIME);
            collectionTimeClickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(collectionTimeColumnDTO.getDType()));
            collectionTimeClickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(collectionTimeClickhouseColumnDTO);
        }
        ColumnDTO seqColumnDTO = columnDTOMap.get(AsyncTaskServiceImpl.SEQ);
        if (Objects.nonNull(seqColumnDTO)) {
            ClickhouseColumnDTO collectionIdClickhouseColumnDTO = new ClickhouseColumnDTO();
            collectionIdClickhouseColumnDTO.setColumnId(seqColumnDTO.getId());
            collectionIdClickhouseColumnDTO.setCol(seqColumnDTO.getCol());
            collectionIdClickhouseColumnDTO.setName(AsyncTaskServiceImpl.COLLECTION_ID);
            collectionIdClickhouseColumnDTO.setDataType(columnDataTypeToClickhouseType(seqColumnDTO.getDType()));
            collectionIdClickhouseColumnDTO.setDateType(DateTypeEnum.DateType.UNSPECIFIED);
            clickhouseColumnDTOList.add(collectionIdClickhouseColumnDTO);
        }

        return clickhouseColumnDTOList;
    }

    /**
     * 普通项目获取 ClickHouse 数据表数据
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/7/21 15:18
     */
    public ClickHouseDTO getClickhouseData(String worktableId, List<ClickhouseColumnDTO> clickhouseColumnDTOList, Integer skip) {
        if (log.isInfoEnabled()) {
            log.info("[Txtanls] {} 获取 clickhouse 数据", worktableId);
        }
        if (CollectionUtils.isEmpty(clickhouseColumnDTOList)) {
            if (log.isInfoEnabled()) {
                log.info("[Txtanls] {} 待获取的列信息数组数据为空", worktableId);
            }
            return null;
        }
        return clickhouseGrpcService.queryClickHouse(worktableId, skip, clickhouseColumnDTOList, new ArrayList<>());
    }

    /**
     * 问卷项目获取 ClickHouse 数据表数据
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/7/21 15:18
     */
    public ClickHouseDTO getClickhouseData(String worktableId, List<ClickhouseColumnDTO> clickhouseColumnDTOList, Integer skip,
                                           List<Filter> filterList) {
        if (log.isInfoEnabled()) {
            log.info("[Txtanls] {} 获取 clickhouse 数据", worktableId);
        }
        if (CollectionUtils.isEmpty(clickhouseColumnDTOList)) {
            if (log.isInfoEnabled()) {
                log.info("[Txtanls] {} 待获取的列信息数组数据为空", worktableId);
            }
            return null;
        }
        return clickhouseGrpcService.queryClickHouse(worktableId, skip, clickhouseColumnDTOList, filterList);
    }

    /**
     * 问卷项目获取clickhouse查询使用的时间过滤器
     *
     * @param columnDTO 问卷项目 time 字段的信息
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 时间过滤器
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/7/21 15:20
     */
    public List<Filter> getTimeFilter(ColumnDTO columnDTO, String startTime, String endTime) {
        List<Filter> result = new ArrayList<>();
        if (!ObjectUtils.isEmpty(startTime)) {
            Filter.Builder builder = Filter.newBuilder();
            builder.setCol(columnDTO.getCol());
            builder.setOption(OptionEnum.Option.GT);
            builder.addAllValues(Arrays.asList(startTime));
            builder.setDataType(DataTypeEnum.DataType.DATETIME);
            result.add(builder.buildPartial());
        }
        if (!ObjectUtils.isEmpty(endTime)) {
            Filter.Builder builder = Filter.newBuilder();
            builder.setCol(columnDTO.getCol());
            builder.setOption(OptionEnum.Option.LT);
            builder.addAllValues(Arrays.asList(endTime));
            builder.setDataType(DataTypeEnum.DataType.DATETIME);
            result.add(builder.buildPartial());
        }
        return result;
    }


    /**
     * column数据类型 转为 clickhouse数据类型
     *
     * @param columnType column数据类型
     * @return 对应的clickhouse数据类型
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/7/21 15:21
     */
    private DataTypeEnum.DataType columnDataTypeToClickhouseType(Integer columnType) {
        ColumnDataTypeEnum columnDateType = ColumnDataTypeEnum.getByIndex(columnType);
        if (Objects.isNull(columnDateType)) {
            return DataTypeEnum.DataType.UNRECOGNIZED;
        }
        if (ColumnDataTypeEnum.INT.equals(columnDateType)) {
            return DataTypeEnum.DataType.NUMBER;
        }
        if (ColumnDataTypeEnum.STRING.equals(columnDateType)) {
            return DataTypeEnum.DataType.STRING;
        }
        if (ColumnDataTypeEnum.DATETIME.equals(columnDateType)) {
            return DataTypeEnum.DataType.DATETIME;
        }
        return DataTypeEnum.DataType.UNRECOGNIZED;
    }

    public Filter getSurveyStatusFilter() {
        Filter.Builder builder = Filter.newBuilder();
        String fieldName = "status";
        builder.setCol(fieldName);
        builder.setOption(OptionEnum.Option.EQ);
        String fieldValue = "成功完成";
        builder.addAllValues(Collections.singletonList(fieldValue));
        builder.setDataType(DataTypeEnum.DataType.STRING);
        return builder.buildPartial();
    }
}
